﻿
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using Red.Controls.Utils;
using Red.Core;

namespace Red.Controls.Shell
{
    internal static class CategoryCommands
    {
        public static RedCommand MoveToNextItem = new RedCommand();
    }


    /// <summary>
    ///     Interaction logic for Category.xaml
    /// </summary>
    public partial class CategoryControl : UserControl
    {
        public CategoryBase Owner { get; set; }

        public CategoryControl()
        {
            InitializeComponent();
        }

        private void Button_Click( object sender, RoutedEventArgs e )
        {
            Owner.IsExpanded = !Owner.IsExpanded;
        }

        private void Header_MouseLeftButtonDown( object sender, MouseButtonEventArgs e )
        {
            if ( e.ClickCount == 2 )
            {
                Owner.IsExpanded = !Owner.IsExpanded;
            }
        }

        private void MoveToNextItem_Executed( object sender, ExecutedRoutedEventArgs e )
        {
            FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;
            TraversalRequest request = new TraversalRequest(focusDirection);
            UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

            if ( elementWithFocus != null )
                if ( elementWithFocus.MoveFocus( request ) )
                    e.Handled = true;
        }
    }

    /// <summary>
    ///     Base class handling common functionality for Categories
    /// </summary>
    public abstract class CategoryBase : ElementFacade<CategoryControl>
    {
        #region Data

        private const string _defaultHeaderBackground = "AccentColorBrush";
        
        #endregion Data

        #region Properties

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register( "Title", typeof( string ), typeof( CategoryBase ),
                new FrameworkPropertyMetadata( null ) );

        public static readonly DependencyProperty IsExpandedProperty =
            DependencyProperty.Register( "IsExpanded", typeof( bool ), typeof( CategoryBase ),
                new FrameworkPropertyMetadata( true, ExpandedPropertyChanged ) );

        public static readonly DependencyProperty HeaderBackgroundProperty =
            DependencyProperty.Register( "HeaderBackground", typeof( Brush ), typeof( CategoryBase ) );

        public static readonly DependencyProperty HeaderVisibilityProperty =
            DependencyProperty.Register( "HeaderVisibility", typeof( Visibility ), typeof( CategoryBase ) );

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register( "SelectedItem", typeof( object ), typeof( CategoryBase ) );

        public Brush HeaderBackground
        {
            get { return (Brush)GetValue( HeaderBackgroundProperty ); }
            set { SetValue( HeaderBackgroundProperty, value ); }
        }

        /// <summary>
        /// Visibility setting of the category header
        /// </summary>
        public Visibility HeaderVisibility
        {
            get { return (Visibility)GetValue( HeaderVisibilityProperty ); }
            set { SetValue( HeaderVisibilityProperty, value ); }
        }


        /// <summary>
        /// Category title, displayed in header
        /// </summary>
        public string Title
        {
            get { return (string)GetValue( TitleProperty ); }
            set { SetValue( TitleProperty, value ); }
        }

        /// <summary>
        /// Is the category expanded (true) or folded (false)
        /// </summary>
        public bool IsExpanded
        {
            get { return (bool)GetValue( IsExpandedProperty ); }
            set { SetValue( IsExpandedProperty, value ); }
        }

        /// <summary>
        ///     Item that is currently selected
        /// </summary>
        public object SelectedItem
        {
            get { return GetValue( SelectedItemProperty ); }
            set { SetValue( SelectedItemProperty, value ); }
        }

        #endregion Properties

        #region C-tor

        public CategoryBase()
        {
            Element.Owner = this;
            Loaded += CategoryBase_Loaded;
            Element._elementsList.SetBinding( ListBox.SelectedItemProperty, new Binding( "SelectedItem" ) { Source = this, Mode=BindingMode.TwoWay } );
            Element._elementsList.SelectionChanged += ElementsList_SelectionChanged;
        }

        #endregion C-tor

        #region Event handlers

        private void CategoryBase_Loaded( object sender, RoutedEventArgs e )
        {
            if ( HeaderBackground == null )
            {
                SetResourceReference( HeaderBackgroundProperty, _defaultHeaderBackground );
            }
        }

        private void ElementsList_SelectionChanged( object sender, SelectionChangedEventArgs e )
        {
            var stacker = Helpers.FindVisualAncestorOfType<Stacker>( this );
            if ( stacker != null )
            {
                stacker.SynchronizeSelection( this );
            }
        }

        private static void ExpandedPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            var category = d as CategoryBase;
            if ( true.Equals( e.NewValue ) )
            {
                category.Element._elementsList.Visibility = Visibility.Visible;
            }
            else
            {
                category.Element._elementsList.Visibility = Visibility.Collapsed;
            }
        }

        #endregion Event handlers
    }

    /// <summary>
    ///     Category containing UIElements. Use it to manually create UI. May contain sub-Categories
    /// </summary>
    [ContentProperty("Content")]
    public class Category : CategoryBase
    {
        #region Embedded types
        
        /// <summary>
        ///     This selector has to be used to apply different templates for Sub-Categories and everything else. 
        ///     Apparently, the default route of defining two DataTemplates with different DataType doesn't work for the types 
        ///     being a FrameWork/UIElements - ListView's ItemDataSelector has to treat them differently.
        /// </summary>
        private class TemplateSelector : DataTemplateSelector
        {
            public override DataTemplate SelectTemplate( object item, DependencyObject container )
            {
                var c = container as FrameworkElement;
                if ( item is Category )
                {
                    return (DataTemplate)c.FindResource( "SubCategoryTemplate" );
                }
                else if ( item is UIElement )
                {
                    return (DataTemplate)c.FindResource( "StandardTemplate" );
                }

                // fall-back to default mechanism
                return base.SelectTemplate( item, container );
            }
        }
        
        #endregion Embedded types
        
        #region Properties
        
        public new static readonly DependencyProperty ContentProperty =
            DependencyProperty.Register( "Content", typeof( ObservableCollection<UIElement> ), typeof( Category ) );

        /// <summary>
        ///     Elements contained in this Category
        /// </summary>
        public new ObservableCollection<UIElement> Content
        {
            get { return (ObservableCollection<UIElement>)GetValue( ContentProperty ); }
            set { SetValue( ContentProperty, value ); }
        }
        
        #endregion Properties

        #region C-tor
        
        public Category()
        {
            Content = new ObservableCollection<UIElement>(); // WARNING: This CANNOT be put as a property default value
            Element._elementsList.ItemTemplateSelector = new TemplateSelector();
            Element._elementsList.SetBinding( ListBox.ItemsSourceProperty, new Binding( "Content" ) { Source = this } );
        }
        
        #endregion C-tor
    }
}
